/*
 * Copyright [2022] [https://www.xiaonuo.vip]
 *
 * Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：
 *
 * 1.请不要删除和修改根目录下的LICENSE文件。
 * 2.请不要删除和修改Snowy源码头部的版权声明。
 * 3.本项目代码可免费商业使用，商业使用请保留源码和相关描述文件的项目出处，作者声明等。
 * 4.分发源码时候，请注明软件出处 https://www.xiaonuo.vip
 * 5.不可二次分发开源参与同类竞品，如有想法可联系团队xiaonuobase@qq.com商议合作。
 * 6.若您的项目无法满足以上几点，需要更多功能代码，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package cn.lixunims.ims.modular.inventory.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.lixunims.common.util.CommonDownloadUtil;
import cn.lixunims.common.util.CommonResponseUtil;
import cn.lixunims.ims.modular.basics.entity.ImsProduct;
import cn.lixunims.ims.modular.basics.entity.ImsSupplier;
import cn.lixunims.ims.modular.basics.entity.ImsWarehouse;
import cn.lixunims.ims.modular.basics.service.ImsProductService;
import cn.lixunims.ims.modular.basics.service.ImsSupplierService;
import cn.lixunims.ims.modular.basics.service.ImsWarehouseService;
import cn.lixunims.ims.modular.inventory.entity.ImsInventoryChangeLog;
import cn.lixunims.ims.modular.inventory.entity.ImsRealTimeInventory;
import cn.lixunims.ims.modular.inventory.mapper.ImsRealTimeInventoryMapper;
import cn.lixunims.ims.modular.inventory.param.*;
import cn.lixunims.ims.modular.inventory.service.ImsInventoryChangeLogService;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.alibaba.excel.write.style.row.AbstractRowHeightStyleStrategy;
import com.aliyun.oss.ServiceException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import cn.lixunims.common.enums.CommonSortOrderEnum;
import cn.lixunims.common.exception.CommonException;
import cn.lixunims.common.page.CommonPageRequest;
import cn.lixunims.ims.modular.inventory.service.ImsRealTimeInventoryService;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 实时库存Service接口实现类
 *
 * @author YouDong
 * @date  2024/09/19 12:51
 **/
@Service
public class ImsRealTimeInventoryServiceImpl extends ServiceImpl<ImsRealTimeInventoryMapper, ImsRealTimeInventory> implements ImsRealTimeInventoryService {


    @Autowired
    private ImsWarehouseService imsWarehouseService;

    @Autowired
    private ImsProductService imsProductService;

    @Autowired
    private ImsSupplierService imsSupplierService;
    @Autowired
    private ImsInventoryChangeLogService imsInventoryChangeLogService;

    @Override
    public Page<ImsRealTimeInventory> page(ImsRealTimeInventoryPageParam imsRealTimeInventoryPageParam) {
        QueryWrapper<ImsRealTimeInventory> queryWrapper = new QueryWrapper<ImsRealTimeInventory>().checkSqlInjection();

        // 分类查询
        if (ObjectUtil.isNotEmpty(imsRealTimeInventoryPageParam.getWareId())) {
            String wareId = imsRealTimeInventoryPageParam.getWareId();
            if (StrUtil.isNotBlank(wareId) && !wareId.equals("0")) {
                // 获取所有子分类ID
                List<String> productTypeIds = getAllChildTypeIds(wareId);
                productTypeIds.add(wareId); // 包括当前分类
                queryWrapper.lambda().in(ImsRealTimeInventory::getWareId, productTypeIds);
            }
        }
        // 供应商
        queryWrapper.lambda().eq(ObjectUtil.isNotNull(imsRealTimeInventoryPageParam.getSupplierId()), ImsRealTimeInventory::getSupplierId, imsRealTimeInventoryPageParam.getSupplierId());

        if(ObjectUtil.isAllNotEmpty(imsRealTimeInventoryPageParam.getSortField(), imsRealTimeInventoryPageParam.getSortOrder())) {
            CommonSortOrderEnum.validate(imsRealTimeInventoryPageParam.getSortOrder());
            queryWrapper.orderBy(true, imsRealTimeInventoryPageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
                    StrUtil.toUnderlineCase(imsRealTimeInventoryPageParam.getSortField()));
        } else {
            queryWrapper.lambda().orderByAsc(ImsRealTimeInventory::getId);
        }
        Page<ImsRealTimeInventory> page = this.page(CommonPageRequest.defaultPage(), queryWrapper);
        List<ImsRealTimeInventory> records = page.getRecords();
        if (records.isEmpty()) {
            return page;
        }


        // 关联仓库信息
        List<String> wareIds = CollStreamUtil.toList(records, ImsRealTimeInventory::getWareId);
        List<ImsWarehouse> warehouseList = imsWarehouseService.lambdaQuery().in(ImsWarehouse::getWareId, wareIds).list();

        // 关联商品信息
        List<String> productIds = CollStreamUtil.toList(records, ImsRealTimeInventory::getProductId);
        List<ImsProduct> productList = imsProductService.lambdaQuery().in(ImsProduct::getProductId, productIds).list();

        // 关联供应商信息
        List<String> supplierIds = CollStreamUtil.toList(records, ImsRealTimeInventory::getSupplierId);
        List<ImsSupplier> imsWarehouseList = imsSupplierService.lambdaQuery().in(ImsSupplier::getSupplierId, supplierIds).list();


        // 批量查询关联信息
        records.forEach(imsRealTimeInventory -> {
            // 关联供应商，商品，仓库
            imsRealTimeInventory.setSupplier(imsWarehouseList.stream().filter(imsSupplier -> imsSupplier.getSupplierId().equals(imsRealTimeInventory.getSupplierId())).findFirst().orElse(null));
            imsRealTimeInventory.setProduct(productList.stream().filter(imsProduct -> imsProduct.getProductId().equals(imsRealTimeInventory.getProductId())).findFirst().orElse(null));
            imsRealTimeInventory.setWarehouse(warehouseList.stream().filter(ware -> ware.getWareId().equals(imsRealTimeInventory.getWareId())).findFirst().orElse(null));
        });


        return page;
    }
    /**
     * 获取某个分类的所有子分类 ID
     * @param productTypeId
     * @return
     */
    private List<String> getAllChildTypeIds(String productTypeId) {
        List<String> childIds = new ArrayList<>();
        // 获取直接子分类
        List<ImsWarehouse> childTypes = imsWarehouseService.list(new QueryWrapper<ImsWarehouse>()
                .lambda().eq(ImsWarehouse::getParentId, productTypeId));

        for (ImsWarehouse childType : childTypes) {
            String childId = childType.getWareId();
            childIds.add(childId);
            // 递归获取子分类的子分类
            List<String> grandChildIds = getAllChildTypeIds(childId);
            childIds.addAll(grandChildIds);
        }

        return childIds;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(ImsRealTimeInventoryAddParam imsRealTimeInventoryAddParam) {
        // TODO 库存日志


        ImsRealTimeInventory imsRealTimeInventory = BeanUtil.toBean(imsRealTimeInventoryAddParam, ImsRealTimeInventory.class);
        this.save(imsRealTimeInventory);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(ImsRealTimeInventoryEditParam imsRealTimeInventoryEditParam) {
        ImsRealTimeInventory imsRealTimeInventory = this.queryEntity(imsRealTimeInventoryEditParam.getId());
        BeanUtil.copyProperties(imsRealTimeInventoryEditParam, imsRealTimeInventory);
        this.updateById(imsRealTimeInventory);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<ImsRealTimeInventoryIdParam> imsRealTimeInventoryIdParamList) {
        // 执行删除
        // this.removeByIds(CollStreamUtil.toList(imsRealTimeInventoryIdParamList, ImsRealTimeInventoryIdParam::getId));
    }

    @Override
    public List<ImsRealTimeInventory> detail(ImsRealTimeInventoryIdParam imsRealTimeInventoryIdParam) {
        List<ImsRealTimeInventory> imsRealTimeInventory = this.lambdaQuery()
                .eq(ImsRealTimeInventory::getProductId, imsRealTimeInventoryIdParam.getProductId())
                .gt(ImsRealTimeInventory::getCount, 0)
                .list();
        if (imsRealTimeInventory.isEmpty()) {
            throw new CommonException("当前商品暂无库存，请先进行商品入库");
        }
        // 查询关联信息
        List<String> wareIds = CollStreamUtil.toList(imsRealTimeInventory, ImsRealTimeInventory::getWareId);
        List<ImsWarehouse> warehouseList = imsWarehouseService.lambdaQuery().in(ImsWarehouse::getWareId, wareIds).list();
        imsRealTimeInventory.forEach(item -> {
            item.setWarehouse(warehouseList.stream().filter(ware -> ware.getWareId().equals(item.getWareId())).findFirst().orElse(null));
        });

        return imsRealTimeInventory;
    }

    @Override
    public ImsRealTimeInventory queryEntity(String id) {
        ImsRealTimeInventory imsRealTimeInventory = this.getById(id);
        if(ObjectUtil.isEmpty(imsRealTimeInventory)) {
            throw new CommonException("实时库存不存在，id值为：{}", id);
        }
        return imsRealTimeInventory;
    }

    @Override
    public void exportInfo(HttpServletResponse response) throws IOException {
        File tempFile = null;
        try {
            QueryWrapper<ImsRealTimeInventory> queryWrapper = new QueryWrapper<ImsRealTimeInventory>().checkSqlInjection();
            String fileName = "利讯进销存实时库存清单.xlsx";
            List<ImsRealTimeInventory> inventoryList = this.list(queryWrapper);
            if(ObjectUtil.isEmpty(inventoryList)) {
                throw new CommonException("无数据可导出");
            }
            // transService.transBatch(inventoryList);
            List<ImsRealTimeInventory> exportResultList = inventoryList.stream().collect(Collectors.toList());


            // 处理状态
            for (ImsRealTimeInventory imsProduct : exportResultList) {
                if (imsProduct.getStatus().equals("ENABLE")) {
                    imsProduct.setStatus("启用");
                } else {
                    imsProduct.setStatus("禁用");
                }

                // 商品，供应商，仓库
                String productId = imsProduct.getProductId();
                ImsProduct product = imsProductService.lambdaQuery().eq(ImsProduct::getProductId, productId).one();
                imsProduct.setProductId(product.getProductName());

                String supplierId = imsProduct.getSupplierId();
                ImsSupplier supplier = imsSupplierService.lambdaQuery().eq(ImsSupplier::getSupplierId, supplierId).one();
                imsProduct.setSupplierId(supplier.getSupplierName());

                String wareId= imsProduct.getWareId();
                ImsWarehouse warehouse = imsWarehouseService.lambdaQuery().eq(ImsWarehouse::getWareId, wareId).one();
                imsProduct.setWareId(warehouse.getWareName());

            }





            // 创建临时文件
            tempFile = FileUtil.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName);

            // 头的策略
            WriteCellStyle headWriteCellStyle = new WriteCellStyle();
            WriteFont headWriteFont = new WriteFont();
            headWriteFont.setFontHeightInPoints((short) 14);
            headWriteCellStyle.setWriteFont(headWriteFont);
            // 水平垂直居中
            headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            headWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);

            // 内容的策略
            WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
            // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定
            contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
            // 内容背景白色
            contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
            WriteFont contentWriteFont = new WriteFont();

            // 内容字体大小
            contentWriteFont.setFontHeightInPoints((short) 12);
            contentWriteCellStyle.setWriteFont(contentWriteFont);

            //设置边框样式，细实线
            contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
            contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
            contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
            contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);

            // 水平垂直居中
            contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
            contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);

            // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
            HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle,
                    contentWriteCellStyle);

            // 写excel
            EasyExcel.write(tempFile.getPath(), ImsRealTimeInventory.class)
                    // 自定义样式
                    .registerWriteHandler(new AbstractColumnWidthStyleStrategy() {
                        @Override
                        protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
                            Sheet sheet = writeSheetHolder.getSheet();
                            sheet.setColumnWidth(cell.getColumnIndex(), 20 * 256); // 设置所有列宽为30个字符宽度
                        }
                    })
                    // 自动列宽
                    .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                    // 设置第一行字体
                    .registerWriteHandler(new CellWriteHandler() {
                        @Override
                        public void afterCellDispose(CellWriteHandlerContext context) {
                            WriteCellData<?> cellData = context.getFirstCellData();
                            WriteCellStyle writeCellStyle = cellData.getOrCreateStyle();
                            Integer rowIndex = context.getRowIndex();
                            if(rowIndex == 0) {
                                WriteFont headWriteFont = new WriteFont();
                                headWriteFont.setFontName("宋体");
                                headWriteFont.setBold(true);
                                headWriteFont.setFontHeightInPoints((short) 16);
                                writeCellStyle.setWriteFont(headWriteFont);
                            }
                        }
                    })
                    // 设置表头行高
                    .registerWriteHandler(new AbstractRowHeightStyleStrategy() {
                        @Override
                        protected void setHeadColumnHeight(Row row, int relativeRowIndex) {
                            if(relativeRowIndex == 0) {
                                // 表头第一行
                                row.setHeightInPoints(34);
                            } else {
                                // 表头其他行
                                row.setHeightInPoints(30);
                            }
                        }
                        @Override
                        protected void setContentColumnHeight(Row row, int relativeRowIndex) {
                            // 内容行
                            row.setHeightInPoints(20);
                        }
                    })
                    .sheet("库存信息")
                    .relativeHeadRowIndex(1)
                    .doWrite(exportResultList);
            CommonDownloadUtil.download(tempFile, response);
        } catch (Exception e) {
            log.error(">>> 库存导出失败：", e);
            CommonResponseUtil.renderError(response, "库存导出失败");
        } finally {
            FileUtil.del(tempFile);
        }

    }

}
